﻿using System.IO;
using System.Linq;
using System.Windows.Controls;
using System.Windows.Input;
using System.Xml;
using ICSharpCode.AvalonEdit;
using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.AvalonEdit.Highlighting.Xshd;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Peter.Controls;
using Peter.Logic.AvalonEdit;

namespace Peter.Tests.Controls
{
   /// <summary>
   /// Test cases for the code editor.
   /// </summary>
   [TestClass]
   public class CodeEditorTests
   {
      /// <summary>
      /// Gets or Sets the text context.
      /// </summary>
      public TestContext TestContext { get; set; }

      /// <summary>
      /// Tests the constructor for the code editor.
      /// Makes sure the appropriate items are setup.
      /// </summary>
      [TestMethod]
      public void CodeEditorRenderersTest ()
      {
         var target = new CodeEditor();
         var colorRenderer = target.TextArea.TextView.BackgroundRenderers.FirstOrDefault (
            r => r is ColorBackgroundRenderer);
         var braceRenderer = target.TextArea.TextView.BackgroundRenderers.FirstOrDefault (
            r => r is HighlightBracesBackgroundRenderer);
         var wordRenderer = target.TextArea.TextView.BackgroundRenderers.FirstOrDefault (
            r => r is HighlightCurrentWordBackgroundRenderer);
         Assert.IsNotNull (colorRenderer);
         Assert.IsNotNull (braceRenderer);
         Assert.IsNotNull (wordRenderer);
         target.Close();
         colorRenderer = target.TextArea.TextView.BackgroundRenderers.FirstOrDefault (
            r => r is ColorBackgroundRenderer);
         braceRenderer = target.TextArea.TextView.BackgroundRenderers.FirstOrDefault (
            r => r is HighlightBracesBackgroundRenderer);
         wordRenderer = target.TextArea.TextView.BackgroundRenderers.FirstOrDefault (
            r => r is HighlightCurrentWordBackgroundRenderer);
         target.Close ();
         Assert.IsNull (colorRenderer);
         Assert.IsNull (braceRenderer);
         Assert.IsNull (wordRenderer);
      }

      /// <summary>
      /// Test the context menu setup of the code editor.
      /// </summary>
      [TestMethod]
      public void CodeEditorContextMenuTest ()
      {
         var target = new CodeEditor ();
         var contextMenu = target.ContextMenu;
         var menuItem = (MenuItem) contextMenu.Items [0];
         Assert.IsNotNull (menuItem);
         Assert.AreEqual ("Edit", menuItem.Header);
         Assert.IsNull (menuItem.Command);

         menuItem = (MenuItem) contextMenu.Items [2];
         Assert.IsNotNull (menuItem);
         Assert.AreEqual (ApplicationCommands.Undo.Text, menuItem.Header);
         Assert.AreEqual (ApplicationCommands.Undo, menuItem.Command);

         menuItem = (MenuItem)contextMenu.Items[3];
         Assert.IsNotNull (menuItem);
         Assert.AreEqual (ApplicationCommands.Redo.Text, menuItem.Header);
         Assert.AreEqual (ApplicationCommands.Redo, menuItem.Command);

         menuItem = (MenuItem)contextMenu.Items[5];
         Assert.IsNotNull (menuItem);
         Assert.AreEqual (ApplicationCommands.Cut.Text, menuItem.Header);
         Assert.AreEqual (ApplicationCommands.Cut, menuItem.Command);

         menuItem = (MenuItem)contextMenu.Items[6];
         Assert.IsNotNull (menuItem);
         Assert.AreEqual (ApplicationCommands.Copy.Text, menuItem.Header);
         Assert.AreEqual (ApplicationCommands.Copy, menuItem.Command);

         menuItem = (MenuItem)contextMenu.Items[7];
         Assert.IsNotNull (menuItem);
         Assert.AreEqual (ApplicationCommands.Paste.Text, menuItem.Header);
         Assert.AreEqual (ApplicationCommands.Paste, menuItem.Command);

         menuItem = (MenuItem)contextMenu.Items[8];
         Assert.IsNotNull (menuItem);
         Assert.AreEqual ("Delete Line", menuItem.Header);
         Assert.AreEqual (AvalonEditCommands.DeleteLine, menuItem.Command);
         Assert.AreEqual (target.TextArea, menuItem.CommandTarget);

         menuItem = (MenuItem)contextMenu.Items[9];
         Assert.IsNotNull (menuItem);
         Assert.AreEqual (ApplicationCommands.SelectAll.Text, menuItem.Header);
         Assert.AreEqual (ApplicationCommands.SelectAll, menuItem.Command);
         target.Close ();
      }

      /// <summary>
      /// Tests the open method.
      /// </summary>
      [TestMethod]
      public void CodeEditorOpenTest ()
      {
         var target = new CodeEditor ();
         var filePath = Path.Combine (this.TestContext.TestDir, "Testfile.txt");
         var file = File.CreateText (filePath);
         file.Write ("Hello World - Open!");
         file.Flush();
         file.Close();
         Assert.IsTrue (target.OpenFile (new FileInfo (filePath)));
         Assert.AreEqual ("Hello World - Open!", target.Text);
         target.Close ();
         File.Delete (filePath);
      }

      /// <summary>
      /// Tests the open method.
      /// </summary>
      [TestMethod]
      public void CodeEditorOpenMultipleTest ()
      {
         var target = new CodeEditor ();
         // Create three files...
         var filePath1 = Path.Combine (this.TestContext.TestDir, "Testfile1.txt");
         var file1 = File.CreateText (filePath1);
         file1.Write ("Hello World - Open1!");
         file1.Flush ();
         file1.Close ();
         var filePath2 = Path.Combine (this.TestContext.TestDir, "Testfile2.txt");
         var file2 = File.CreateText (filePath2);
         file2.Write ("Hello World - Open2!");
         file2.Flush ();
         file2.Close ();
         var filePath3 = Path.Combine (this.TestContext.TestDir, "Testfile3.txt");
         var file3 = File.CreateText (filePath3);
         file3.Write ("Hello World - Open3!");
         file3.Flush ();
         file3.Close ();

         // Sequentially open the files...
         Assert.IsTrue (target.OpenFile (new FileInfo (filePath1)));
         Assert.AreEqual ("Hello World - Open1!", target.Text);
         File.Delete (filePath1);

         Assert.IsTrue (target.OpenFile (new FileInfo (filePath2)));
         Assert.AreEqual ("Hello World - Open2!", target.Text);
         File.Delete (filePath2);

         Assert.IsTrue (target.OpenFile (new FileInfo (filePath3)));
         Assert.AreEqual ("Hello World - Open3!", target.Text);
         File.Delete (filePath3);
         target.Close ();
      }

      /// <summary>
      /// Tests the open method.
      /// </summary>
      [TestMethod]
      public void CodeEditorOpenLockTest ()
      {
         var target = new CodeEditor ();
         var filePath = Path.Combine (this.TestContext.TestDir, "Testfile.txt");
         var file = File.CreateText (filePath);
         file.Write ("Hello World!");
         Assert.IsFalse (target.OpenFile (new FileInfo (filePath)));
         target.Close ();
         file.Close ();
         File.Delete (filePath);
      }

      /// <summary>
      /// Tests the open method.
      /// </summary>
      [TestMethod]
      public void CodeEditorSaveTest ()
      {
         var target = new CodeEditor ();
         var filePath = Path.Combine (this.TestContext.TestDir, "Testfile.txt");
         target.Text = "Hello World - Save!";
         target.SaveFile(new FileInfo (filePath));
         Assert.IsTrue(File.Exists (filePath));
         Assert.AreEqual ("Hello World - Save!", File.ReadAllText (filePath));
         target.Close ();
         File.Delete (filePath);
      }

      /// <summary>
      /// Tests the open method.
      /// </summary>
      [TestMethod]
      public void CodeEditorHighlightingTest ()
      {
         var target = new CodeEditor ();

         var highlightingPath = this.TestContext.TestDir;
         highlightingPath = highlightingPath.Substring (0, highlightingPath.LastIndexOf ('\\'));
         highlightingPath = highlightingPath.Substring (0, highlightingPath.LastIndexOf ('\\'));
         highlightingPath += "\\Peter\\AvalonEdit.Highlighting\\Ruby.xshd";
         using (var reader = new XmlTextReader (highlightingPath)) {
            var highlighting = HighlightingLoader.Load (reader, HighlightingManager.Instance);
            HighlightingManager.Instance.RegisterHighlighting ("Ruby", new []{ ".rb", ".ru", ".rake" }, highlighting);
         }

         var filePath = Path.Combine (this.TestContext.TestDir, "temp.cs");
         File.Create (filePath).Close ();
         Assert.IsTrue (target.OpenFile (new FileInfo (filePath)));
         Assert.IsNotNull (target.SyntaxHighlighting);
         Assert.AreEqual ("C#", target.SyntaxHighlighting.Name);
         File.Delete (filePath);

         filePath = Path.Combine (this.TestContext.TestDir, "gemfile");
         File.Create(filePath).Close();
         Assert.IsTrue (target.OpenFile (new FileInfo (filePath)));
         Assert.IsNotNull (target.SyntaxHighlighting);
         Assert.AreEqual("Ruby", target.SyntaxHighlighting.Name);
         File.Delete (filePath);
         target.Close ();
      }
   }
}
